package com.gitee.gateway.core.utils;

import io.vertx.core.json.JsonObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Date;
import java.util.Map;

public class Configuration {

    private final static Logger LOGGER = LoggerFactory.getLogger(Configuration.class);

    private static volatile JsonObject global;

    //Method to load config
    public static JsonObject load() {
        if (global == null) {
            synchronized (Configuration.class) {
                if (global == null) {
                    try {
                        global = loadJson("config" + File.separator + "server.yaml");
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
        return global;
    }

    /**
     * 数据库配置项
     */
    public static JsonObject loadDatabase() throws IOException {
        return loadJson("config" + File.separator + "database.yaml");
    }

    /**
     * 加载微服务配置
     *
     * @return
     */
    public static JsonObject loadServices() {
        try {
            return loadJson("config" + File.separator + "services.yaml");
        } catch (IOException e) {
            LOGGER.error("Failed to load services.yaml", e);
            return JsonObject.of();
        }
    }

    public static JsonObject loadJson(String filename) throws IOException {
        String yamlString = Files.readString(Paths.get(filename));
        Yaml yaml = new Yaml(new LoaderOptions());
        Map<Object, Object> config = yaml.load(yamlString);
        return jsonify(config);
    }

    /**
     * Yaml allows map keys of type object, however json always requires key as String,
     * this helper method will ensure we adapt keys to the right type
     *
     * @param yaml yaml map
     * @return json map
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    private static JsonObject jsonify(Map<Object, Object> yaml) {
        if (yaml == null)
            return null;

        final JsonObject json = new JsonObject();

        for (Map.Entry<Object, Object> kv : yaml.entrySet()) {
            Object value = kv.getValue();
            if (value instanceof Map map) {
                value = jsonify(map);
            }
            // snake yaml handles dates as java.util.Date, and JSON does Instant
            if (value instanceof Date date) {
                value = date.toInstant();
            }
            json.put(kv.getKey().toString(), value);
        }

        return json;
    }

    /**
     * get root path of this app
     */
    public static Path getRootPath() {
        String sPath = Configuration.class.getProtectionDomain().getCodeSource().getLocation().getPath();
        File path = new File(sPath);
        if (sPath.endsWith(".jar"))
            return path.getParentFile().getParentFile().toPath();
        else
            return path.getParentFile().getParentFile().getParentFile().toPath();
    }

}
